#ifndef SERVERSIDESYNCHRONIZER_H_
#define SERVERSIDESYNCHRONIZER_H_

#include <string>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "PlayerSynchronizer.h"
#include "PlayerMoves.h"
#include "CommunicationStructs.h"
#include "udp-server/UdpServer.h"
#include "robak.h"

void *sender_func(void *ptr);
void *resolver_func(void *ptr);
void *game_func(void *ptr);

/** \brief ClientSideSynchronizer - Singleton*/
class ServerSideSynchronizer : public PlayerSynchronizer
{
private:
	static ServerSideSynchronizer * instance;
	UdpServer s;
	pthread_mutex_t write_to_shared_mutex;
	pthread_mutex_t allow_sending_mutex;
	SharedMemStruct * shared_thread_memory;
	AppData * data;
private:
	/* private function decl*/
	ServerSideSynchronizer();
	void addPlayerMove(int player_number, Direction & dir);
	void movePlayerOnMap(int player_number);/* moves player according its last direction*/
	void resetSharedMemory(bool flush_ips);/* if flush is true - resets ALL data in shared struct*/
	Direction & getClientLastDirection(int player_number);
public:
	static ServerSideSynchronizer * getInstance();
	std::string * serializePlayerMoves(PlayerMoves *moves);
	void synchronize();
	SharedMemStruct * getSharedMemoryPtr();
	void startThreads();
	void lockSharedMemory();
	void unlockSharedMemory();
	void allowSendingNewPackage();// unlocks mutex, allows sending new package
	void waitForNewPackage();//locks mutex, stops sending thread
	void sendToAllPlayers();
	/* game interaction*/

	void setClientLastDirection(int client, Direction & dir);/**< sets client last dir before new move*/
	int generateAndInitializePlayer();
	void setServerRoundNumber(int number);
	void startGame();
	void restartGame();
	int getPlayersNumber();
	void printDebug();
	void informPlayerGameOver(int player_number);
	void informPlayerGameWin(int player_number);
	void fillPlayerMovesStruct();
	int processPlayersRegistration();
	int resolvePlayerData();
	int getClientUdpNumber(int number);
	 int getPlayerWinLostStatus(int number);
public:
	//inlines
	void setAppData(AppData * app_data)
	{
		data = app_data;
	}
	AppData* getAppData()
	{
		return data;
	}
};

#endif /*SERVERSIDESYNCHRONIZER_H_*/
